package com.dlc.garbagerecyclebox;

import com.dlc.commonbiz.base.callback.DataPackCallback;
import com.dlc.commonbiz.base.serialport.DataPack;
import com.dlc.commonbiz.base.serialport.utils.ByteUtil;
import com.dlc.commonbiz.base.serialport.utils.CheckUtil;
import com.dlc.garbagerecyclebox.bean.DeliveryInfoBean;
import com.dlc.garbagerecyclebox.bean.DeviceInfoBean;
import com.dlc.garbagerecyclebox.bean.HeartBeatBean;
import com.dlc.garbagerecyclebox.bean.ManageMaintainInfoBean;
import com.dlc.garbagerecyclebox.bean.RecyclingInfoBean;
import com.dlc.garbagerecyclebox.log.GarbageRecycleBoxLogFactory;

import java.nio.ByteBuffer;

/**
 * @author :      fangbingran
 * @aescription : 数据解析
 * @date :        2019/07/29  11:24
 */
public class GarbageRecyclerBoxHandleDataPack {

    static boolean handleDataPack(ByteBuffer byteBuffer, byte[] received, int size, DataPackCallback dataPackCallback) {
        if (byteBuffer == null) {
            byteBuffer = ByteBuffer.allocate(1024);
            byteBuffer.clear();
        }
        //从received数组中的0到0+length区域读取数据并使用相对写写入此byteBuffer
        byteBuffer.put(received, 0, size);
        //limit = position;position = 0;mark = -1;
        // 将一个处于存数据状态的缓冲区变为一个处于准备取数据的状态
        byteBuffer.flip();
        int readable;
        while ((readable = byteBuffer.remaining()) >= GarbageRecyclerBoxProtocol.MIN_PACK_LEN) {
            //标记一下当前位置,调用mark()来设置mark=position，再调用reset()可以让position恢复到标记的位置
            byteBuffer.mark();
            int frameStart = byteBuffer.position();
            byte head = byteBuffer.get();
            //校验头部1
            if (head != GarbageRecyclerBoxProtocol.FRAME_HEADER) {
                continue;
            }
            byte head2 = byteBuffer.get();
            //校验头部2
            if (head2 != GarbageRecyclerBoxProtocol.FRAME_HEADER2) {
                continue;
            }
            //校验数据域长度,数据域在第6个位置
            byte[] len = new byte[] { byteBuffer.get(frameStart + GarbageRecyclerBoxProtocol.DATA_LEN_INDEX) };
            //数据域长度
            int dataLen = ByteUtil.byteToInt(len);
            // 总数据长度(实际长度=最小长度(不包含数据域长度)+实际数据长度)
            int total = GarbageRecyclerBoxProtocol.MIN_PACK_LEN + dataLen;
            //当前长度小于实际数据总长度,
            if (readable < total) {
                //重置处理的位置,跳出循环
                byteBuffer.reset();
                break;
            }
            //回到头
            byteBuffer.reset();
            //获取整个包
            byte[] allPack = new byte[total];
            byteBuffer.get(allPack);
            int oXRLen = GarbageRecyclerBoxProtocol.OXR_LEN;
            //为本帧数据包括帧头，源地址，目标地址，数据长度，命令码，协议版本，数据在内的全部数据做异或校验,所以异或的数据是第一位到倒数第二位
            String dataToXOR = CheckUtil.getXOR(ByteUtil.getBytes(allPack, 0, total - oXRLen));
            //获取数据包中的异或值

            String currentXOR = ByteUtil.bytes2HexStr(allPack, total - oXRLen, 1);
            if (dataToXOR.equalsIgnoreCase(currentXOR)) {
                //获取数据码,根据数据,数据码在第六位,所以从8算起
                byte[] data = ByteUtil.getBytes(allPack, GarbageRecyclerBoxProtocol.DATA_INDEX, dataLen);
                byte[] commands = ByteUtil.getBytes(allPack, GarbageRecyclerBoxProtocol.COMMAND_INDEX, GarbageRecyclerBoxProtocol.COMMAND_LEN);
                //最后清掉之前处理过的不合适的数据
                if (dataPackCallback != null) {
                    dataPackCallback.setDataPack(new DataPack(allPack, data, commands));
                }
            } else {
                GarbageRecycleBoxLogFactory.info("异或不相同,dataToXOR:" + dataToXOR + "--currentXOR:" + currentXOR);
                //不一致回调这次帧头之后
                byteBuffer.position(frameStart + 1);
            }
        }
        //最后清掉之前处理过的不合适的数据
        byteBuffer.compact();
        return true;
    }

    public static HeartBeatBean getHeartBeatBean(byte[] allPack, byte[] data, byte[] command) {

        HeartBeatBean heartBeatBean = new HeartBeatBean();
        heartBeatBean.setDataPack(new DataPack(allPack, data, command));
        int cmdCodeNumber = ByteUtil.byteToInt(
            ByteUtil.getBytes(allPack, GarbageRecyclerBoxProtocol.COMMAND_NUMBER_INDEX, GarbageRecyclerBoxProtocol.COMMAND_NUMBER_LEN));
        //主流程
        int deviceAddress = ByteUtil.byteToInt(
            ByteUtil.getBytes(allPack, GarbageRecyclerBoxProtocol.DEVICE_ADDRESS_INDEX, GarbageRecyclerBoxProtocol.DEVICE_ADDRESS_IEN));
        DeviceInfoBean deviceBean = new DeviceInfoBean();
        deviceBean.setCmdCode(command);
        deviceBean.setCmdCodeNumber(cmdCodeNumber);
        deviceBean.setDeviceAddress(deviceAddress);
        byte mainProcessCmd = data[0];
        deviceBean.setMainProcessCmd(mainProcessCmd);
        deviceBean.setExecuteCategory(data[1]);
        //错误码
        deviceBean.setFaultCodeBean(new DeviceInfoBean.FaultCodeBean(ByteUtil.bytes2HexStr(ByteUtil.getBytes(data, 6, 2))));
        //传感器
        DeviceInfoBean.SensorStatusBean sensorStatusBean = new DeviceInfoBean.SensorStatusBean(ByteUtil.getBytes(data, 8, 24));
        sensorStatusBean.setDeviceAddress(deviceAddress);
        deviceBean.setSensorStatusBean(sensorStatusBean);

        //工作流程
        if (deviceBean.isDeliveryProcess()) {
            //投递
            DeliveryInfoBean deliveryInfoBean = new DeliveryInfoBean(deviceBean);
            deliveryInfoBean.setExecuteAction(data[1]);
            String hexStr = ByteUtil.bytes2HexStr(ByteUtil.getBytes(data, 2, 4));
            deliveryInfoBean.setAmount(ByteUtil.hexStr2Float(hexStr));
            heartBeatBean.setDeliveryInfoBean(deliveryInfoBean);
        } else if (deviceBean.isRecyclingProcess()) {
            //回收
            RecyclingInfoBean recyclingStatusBean = new RecyclingInfoBean(deviceBean);
            recyclingStatusBean.setExecuteAction(data[1]);
            recyclingStatusBean.setAmount(ByteUtil.hexStr2Float(ByteUtil.getBytes(data, 2, 4)));
            heartBeatBean.setRecyclingInfoBean(recyclingStatusBean);
        } else if (deviceBean.isManageMaintainProcess()) {
            //管理
            ManageMaintainInfoBean manageMaintainBean = new ManageMaintainInfoBean(deviceBean);
            manageMaintainBean.setExecuteAction(data[1], ByteUtil.getBytes(data, 2, 4));
            heartBeatBean.setManageMaintainInfoBean(manageMaintainBean);
        } else {
            heartBeatBean.setDeviceInfoBean(deviceBean);
        }
        return heartBeatBean;
    }

    public static HeartBeatBean getVisionHeartBeatBean(byte[] allPack, byte[] data, byte[] command) {

        HeartBeatBean heartBeatBean = new HeartBeatBean();
        heartBeatBean.setDataPack(new DataPack(allPack, data, command));
        int cmdCodeNumber = ByteUtil.byteToInt(
            ByteUtil.getBytes(allPack, GarbageRecyclerBoxProtocol.COMMAND_NUMBER_INDEX, GarbageRecyclerBoxProtocol.COMMAND_NUMBER_LEN));
        int deviceAddress = ByteUtil.byteToInt(
            ByteUtil.getBytes(allPack, GarbageRecyclerBoxProtocol.DEVICE_ADDRESS_INDEX, GarbageRecyclerBoxProtocol.DEVICE_ADDRESS_IEN));
        DeviceInfoBean deviceBean = new DeviceInfoBean();
        deviceBean.setCmdCode(command);
        deviceBean.setCmdCodeNumber(cmdCodeNumber);
        deviceBean.setDeviceAddress(deviceAddress);
        heartBeatBean.setDeviceInfoBean(deviceBean);
        return heartBeatBean;
    }
}
